package org.joa.examples.philosophers;

import java.util.logging.Logger;

import org.joa.actor.Actor;
import org.joa.actor.exception.RemoteException;
import org.joa.examples.philosophers.generated.Chopstick;
import org.joa.examples.philosophers.generated.ChopstickProxy;
import org.joa.examples.philosophers.generated.Philosopher;
import org.joa.examples.philosophers.generated.PhilosopherProxy;
import org.joa.manager.ActorManager;
import org.joa.util.Callback;

public class Driver {

    private transient static Logger logger = Logger.getLogger(Driver.class.getName());

    protected static class PhilosopherCompletionCallback implements Callback<Void> {
        private Philosopher philosopher;

        public PhilosopherCompletionCallback(Philosopher philosopher) {
            this.philosopher = philosopher;
        }

        @Override
        public void onSuccess(Void result) {
            logger.info("Philosopher " + philosopher.getRemoteActorName() +
                " finished with SUCCESS");
        }

        @Override
        public void onError(Throwable ex) {
            ex.printStackTrace();
            logger
                .info("Philosopher " + philosopher.getRemoteActorName() + " finished with ERROR:");
        }
    }

    protected static class BootActor extends Actor {
        private static final long serialVersionUID = 1L;

        public BootActor() {
            ActorManager.instance.register(this);
        }

        public void start(int philosopherCount) throws RemoteException {
            logger.info("BootActor start philosopherCount = " + philosopherCount);

            logger.info("Creating chopsticks");

            // Create chopsticks
            Chopstick[] chopsticks = new Chopstick[philosopherCount];
            for (int idx = 0; idx < chopsticks.length; idx++) {
                chopsticks[idx] = ChopstickProxy.create(self());
            }

            logger.info("Creating philosophers");

            // Create and start philosophers
            for (int idx = 0; idx < philosopherCount; idx++) {
                final Philosopher philosopher = PhilosopherProxy.create(self());

                Chopstick leftChopstick = chopsticks[idx];
                Chopstick rightChopstick = chopsticks[(idx + 1) % chopsticks.length];

                philosopher.start(leftChopstick, rightChopstick, new PhilosopherCompletionCallback(
                    philosopher));
            }

            ActorManager.instance.shutdown();
        }
    }

    public static void main(String[] args) throws RemoteException {
        BootActor bootActor = new BootActor();
        bootActor.start(2);
    }
}
